# !/usr/bin/env python
# -*- coding:utf-8 -*-

# 导入PyQt6
from PyQt6.QtWidgets import QApplication, QMainWindow, QFileDialog
from PyQt6.QtCore import QTimer, QStandardPaths
from datetime import timedelta,date
from time import time
import random
import re

from view.data import Ui_MainWindow
from view import id
from service.tishi_service import Tishi
from view import compiled_ds         # 界面图标

# ==============================================================================
# view 1.身份证页面
# ==============================================================================


class Data(QMainWindow, Ui_MainWindow):
    """主页面"""

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.comboBox.lineEdit().returnPressed.connect(lambda: self.division(self.timer, self.comboBox))
        self.comboBox.lineEdit().textEdited.connect(self.on_text_changed)  # bug页面，查询模块下拉框，触发模块查询
        self.comboBox.lineEdit().setCompleter(None)  # 关闭自动补全功能
        self.comboBox_2.lineEdit().returnPressed.connect(lambda: self.division(self.timer_2, self.comboBox_2))
        self.comboBox_2.lineEdit().textEdited.connect(self.on_text_changed2)  # bug页面，保存模块下拉框，触发模块查询
        self.comboBox_2.lineEdit().setCompleter(None)  # 关闭自动补全功能
        self.timer = QTimer()
        self.timer_2 = QTimer()

        self.ts = Tishi()  # 提示框
        self.add_division()


    def add_division(self):
        """设置下拉选项"""
        self.comboBox.clear()  # 清空下拉框
        self.comboBox_2.clear()
        self.comboBox_3.clear()
        for result in id.AREA_INFO.keys():  # 将模块名称、ID，写入下拉框选项
            self.comboBox.addItem(result)
            self.comboBox_2.addItem(result)
        for k in id.Agency.keys():
            self.comboBox_3.addItem(k)

    def change(self):
        """页面切换按钮"""
        b = ('toolButton_01', 'toolButton_02')
        button = self.sender().objectName()     # 获取点击的按钮名称
        index_b = b.index(button)
        self.stacked.setCurrentIndex(index_b)   # 切换页面
        for button_name in b:                   # 点击按钮变色
            button_instance = getattr(self, button_name)  # 获取对应名称的 QPushButton 实例
            if button == button_name:
                button_instance.setStyleSheet("""
                QToolButton {
                    background-color: rgb(228, 245, 255);
                    font: 9pt "微软雅黑";
                    border-radius: 8px;
                }""")
            else:
                button_instance.setStyleSheet("""
                    QToolButton {
                        font: 9pt "微软雅黑";
                        border-radius: 8px;
                        }
                    QToolButton:hover:!selected {
                        background-color: rgb(226, 226, 226);
                        }""")

    def on_text_changed(self):
        # 取消之前可能存在的计时器
        if self.timer:
            self.timer.stop()
            self.timer.deleteLater()
        # 创建一个新的计时器，在3秒后触发查询函数
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)  # 设置为单次触发
        self.timer.timeout.connect(lambda: self.division(self.timer, self.comboBox))
        self.timer.start(3000)  # 3秒后触发

    def on_text_changed2(self):
        # 取消之前可能存在的计时器
        if self.timer_2:
            self.timer_2.stop()
            self.timer_2.deleteLater()
        # 创建一个新的计时器，在3秒后触发查询函数
        self.timer_2 = QTimer(self)
        self.timer_2.setSingleShot(True)  # 设置为单次触发
        self.timer_2.timeout.connect(lambda: self.division(self.timer_2, self.comboBox_2))
        self.timer_2.start(3000)  # 3秒后触发

    def division(self, timer, quhua):
        """区划查询"""
        if timer and timer.isActive():  # 关闭并删除计时器（确保不会触发3秒的定时事件）
            timer.stop()
            # timer.deleteLater()
            # timer=None  # 清空计时器引用
        value = quhua.lineEdit().text()  # 获取输入文本

        data = []
        pattern = '.*%s.*' % value      # 用关键字构建模糊匹配的正则表达式
        regex = re.compile(pattern)     # 编译正则表达式
        for item in id.AREA_INFO.keys():
            match = regex.search(item)  # 检查当前项是否与regex匹配。
            if match:
                data.append(item)

        quhua.clear()  # 清空下拉框
        if data:
            for result in data:  # 将模块名称、ID，写入下拉框选项
                quhua.addItem(result)
        else:
            for result in id.AREA_INFO.keys():  # 将区划，写入下拉框选项
                quhua.addItem(result)

    def select_folder(self):
        """选择保存路径，默认下载文件夹"""
        button = self.sender().objectName()             # 获取点击的按钮名称
        b = {'pushButton_7':'path_0', 'pushButton_8':'path_1'}
        pathtext = getattr(self, b[button])             # 获取对应名称的 QPushButton 实例
        downloads_folder = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DownloadLocation)
        directory = QFileDialog.getExistingDirectory(self, "选择文件夹", downloads_folder)
        pathtext.setText(directory)

    def unique_random(self, count):
        """生成指定数量的不重复的随机数，范围在0到365之间（包含0和365）。
        参数:count -- 要生成的随机数的数量，必须满足 1 <= count <= 365。
        返回:一个列表，包含count个范围内不重复的随机数。"""
        return random.sample(range(365), count)


    def get_check_digit(self,id):
        """通过身份证号获取校验码"""
        check_sum=0
        for i in range(0, 17):
            check_sum+=((1 << (17 - i)) % 11) * int(id[i])
        check_digit=(12 - (check_sum % 11)) % 11
        return check_digit if check_digit < 10 else 'X'


    def start_sfz(self):
        """开始生成身份证"""
        sfz_set = set()                                             # 身份证集合
        year = self.spinBox.text()                                  # 获取设置
        numbers = {0: (1,500), 1: (6,5000), 2: (11,10000), 3: (101,100000), 4: (365,364635)}
        number = numbers[self.comboBox_5.currentIndex()]            # 数量级
        count = self.unique_random(number[0])                       # 随机天数。控制数量
        division = id.AREA_INFO.get(self.comboBox.currentText(), '')        # 区划号
        if not division:
            self.ts.xinxi(f"请正确选择地区！")
            return
        if self.path_0.text():                                      # 保存地址
            path = self.path_0.text()
        else:
            path = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DownloadLocation)
        self.daochu.setEnabled(False)       # 按钮置灰

        try:
            sxh = ["%03d" % i for i in range(1, 1000)]      #999个顺序号
            rq = [date.today() + timedelta(days=i) for i in range(365)]  # 先计算日期，一年日期
            rq = [d.strftime('%m%d') for d in rq]           # 然后对每个日期应用 strftime 格式化
            jd = 0

            start_time = time()                     # 记录开始时间
            for r in count:  #range(0, 365):                 # 365天循环
                for s in range(0, 999):             # 999个顺序号循环
                    sfz = str(division)               # 地区项
                    sfz += year                       # 年份项
                    sfz = sfz + rq[r]                 # 日期
                    sfz = sfz + sxh[s]                # 顺序号
                    id_number = sfz +str(self.get_check_digit(sfz))   #  获取校验码
                    sfz_set.add(id_number)
                jd += 1
                jindu = round(jd * 100 / len(count))        # 进度条计算（四舍五入）
                self.progressBar.setValue(jindu)    # 更新进度条的值
                QApplication.processEvents()        # 确保GUI及时更新

            if number[1] < 360000:                  # 在生成集合中，取指定数量身份证
                sfz_set = random.sample(sfz_set, number[1])     # 随机选择指定数量的不重复元素
            with open(f'{path}\\{self.comboBox.currentText()}-{year}年-身份证号.txt', 'w') as sfz:
                for i in sfz_set:
                    sfz.write(f'{i}\n')                 #每行写入身份证

            end_time = time()                           # 记录结束时间
            exec_time_seconds = end_time - start_time   # 计算执行时间，直接保留为秒
            self.ts.xinxi(f"生成完成\n耗时：{exec_time_seconds:.2f} 秒\n文件位于：{path}")

        except Exception as e:
            self.ts.xinxi(f"生成失败:{e}")
        finally:
            self.daochu.setEnabled(True)  # 按钮激活


# ==============================================================================
# view 2.信用代码页面
# ==============================================================================

    def CreateC9(self, code):
        """主体标识码（组织机构代码），校验码生成"""
        weighting_factor = [3, 7, 9, 10, 5, 8, 4, 2]        # 第i位置上的加权因子
        organization_code = code[8:17]              # 第9~17位为主体标识码(组织机构代码)
        ontology_code = organization_code[0:8]      # 本体代码
        tmp_check_code = self.gen_check_code(           # 生成校验码
            weighting_factor, ontology_code, 11, id.ORGANIZATION_CHECK_CODE_DICT)
        return code[:16] + tmp_check_code

    def getSocialCreditCode(self, code):
        """组合最后两位校验码"""
        code = self.CreateC9(code[:16])
        weighting_factor = [1, 3, 9, 27, 19, 26, 16,
                            17, 20, 29, 25, 13, 8, 24, 10, 30, 28]      # 第i位置上的加权因子
        ontology_code = code[0:17]      # 本体代码
        tmp_check_code = self.gen_check_code(                # 计算校验码
            weighting_factor, ontology_code, 31, id.SOCIAL_CREDIT_CHECK_CODE_DICT)
        return code[:17] + tmp_check_code

    def gen_check_code(self, weighting_factor, ontology_code, modulus, check_code_dict):
        """信用代码，校验码生成"""
        total = 0
        for i in range(len(ontology_code)):
            if ontology_code[i].isdigit():
                total += int(ontology_code[i]) * weighting_factor[i]
            else:
                total += check_code_dict[ontology_code[i]
                         ] * weighting_factor[i]
        C9 = modulus - total % modulus
        C9 = 0 if C9 == 31 else C9
        C9 = list(check_code_dict.keys())[
            list(check_code_dict.values()).index(C9)]
        return C9

    def start_xin(self):
        """开始生成统一社会信用代码"""
        xin_set = set()                                     # 信用代码集合
        numbers = {0:500, 1:5000, 2:10000, 3:100000, 4:500000}
        number = numbers[self.comboBox_6.currentIndex()]            # 数量级
        if self.comboBox_4.currentIndex() == 0:             # 机构代码，组成
            jigou_code = [f'{i}' for i in range(0, 10)]     # 0-9 数字列表
        else:
            jigou_code = id.SOCIAL_CREDIT_CHECK_CODE_DICT.keys()
        division = id.AREA_INFO.get(self.comboBox_2.currentText(), '')  # 区划号
        if not division:
            self.ts.xinxi(f"请正确选择地区！")
            return
        if self.path_1.text():                              # 保存地址
            path = self.path_1.text()
        else:
            path = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DownloadLocation)
        category = id.Agency.get(self.comboBox_3.currentText(), '未获取类别编码')     # 登记部门+机构类别编码，2位
        self.daochu_2.setEnabled(False)  # 按钮置灰

        xin8 = str(category) + str(division)     # 信用代码，类别+区划=8位

        try:
            start_time = time()  # 记录开始时间
            jd = 0
            while len(xin_set) < number:            # 控制数量
                code = "".join(random.choices(list(jigou_code), k=8))   # 主体标识码（组织机构代码），随机生成前8位
                code = self.getSocialCreditCode(xin8+code)  # 组合后16，生成2:组织机构代码校验码+信用代码校验码
                xin_set.add(code)

                jd += 1
                jindu = round(jd * 100 / number)  # 进度条计算（四舍五入）
                self.progressBar_2.setValue(jindu)  # 更新进度条的值
                QApplication.processEvents()  # 确保GUI及时更新

            with open(f'{path}\\{self.comboBox_2.currentText()}-统一社会信用代码.txt', 'w') as sfz:
                for x in xin_set:
                    sfz.write(f'{x}\n')  # 每行写入

            end_time = time()  # 记录结束时间
            exec_time_seconds = end_time - start_time  # 计算执行时间，直接保留为秒
            self.ts.xinxi(f"生成完成\n耗时：{exec_time_seconds:.2f} 秒\n文件位于：{path}")

        except Exception as e:
            self.ts.xinxi(f"生成失败:{e}")
        finally:
            self.daochu_2.setEnabled(True)  # 按钮激活

